package error

import (
	"fmt"
	"sync"
)

type Error struct {
	Id  uint16
	Str string
}

func (r *Error) Error() string {
	return r.Str
}

func (r *Error) Code() uint16 {
	return r.Id
}

var idErrMap = map[uint16]error{}
var errMapLock sync.RWMutex
var errIdMap = map[error]uint16{}
var errIdMapLock sync.RWMutex

func NewError(str string, id uint16) *Error {
	err := &Error{id, str}
	errMapLock.Lock()
	if _, ok := idErrMap[id]; ok {
		panic(fmt.Sprintf("NewError id:%v exist", id))
	}
	idErrMap[id] = err
	errIdMap[err] = id
	errMapLock.Unlock()

	return err
}

var (
	Error_Rpc_ExecErr   = NewError("method exec panic", 2)
	Error_Rpc_NotFind   = NewError("method not find", 3)
	Error_Rpc_RespNil   = NewError("result and error are nil", 4)
	Error_Rpc_UnknowErr = NewError("errorcode not find", 5)
	Error_Rpc_CallErr   = NewError("method can not call", 6)
	Error_Rpc_RespType  = NewError("requset type is err", 7)

	//call error
	Error_RpcCall_ConnIsNil      = NewError("call conn is nil", 8)
	Error_RpcCall_HandlerNotFind = NewError("call handle not find", 9)
	Error_RpcCall_ResponseError  = NewError("call response in error", 10)
	Error_RpcCall_TimeOut        = NewError("call response in error", 11)
	Error_RpcCall_RequestError   = NewError("call request is error", 12)

	//cast error
	Error_RpcCast_ConnIsNil      = NewError("cast conn is nil", 13)
	Error_RpcCast_HandlerNotFind = NewError("cast handle not find", 14)
	Error_RpcCast_RequsetError   = NewError("cast request is error", 15)

	Error_RequestMsgRepeat = NewError("msg request repeat", 100)

	Error_DBErr         = NewError("data error", 252)
	Error_UserDataError = NewError("user data error", 253)
	Error_MsgError      = NewError("msg error", 254)
	Error_Unknown       = NewError("unknow error", 255)
	Error_OK            = NewError("ok", 256)
)

func GetError(id uint16) error {
	if id == 0 {
		return nil
	}
	errMapLock.RLock()
	if e, ok := idErrMap[id]; ok {
		errMapLock.RUnlock()
		return e
	}
	errMapLock.RUnlock()
	return Error_Unknown
}

func GetErrId(err error) uint16 {
	errMapLock.RLock()
	defer errMapLock.RUnlock()
	if id, ok := errIdMap[err]; ok {
		return id
	}
	return errIdMap[Error_Unknown]
}

func ConvertError(err error) *Error {
	if errr, ok := err.(*Error); ok {
		return errr
	}
	return Error_Unknown
}
